#include "stm32f4xx.h"                  // Device header
#include "stm32f4xx_conf.h"
#include "Remote.h"
#include "UART.h"
#include "Warming.h"

uint8_t Remote_RxData0[18];//遥控器DMA数据存储器0
uint8_t Remote_RxData1[18];//遥控器DMA数据存储器1

Remote_Data Remote_RxData;//遥控器接收数据
Remote_Data Remote_LastRxData;//遥控器上一次接收数据
uint8_t Remote_Status;//遥控器连接状态,默认未连接(0)
uint8_t Remote_StartFlag=1;//遥控器启动标志位,0-未在启动阶段,1-准备启动,2-第一次接收到数据

/*
 *函数简介:遥控器初始化
 *参数说明:无
 *返回类型:无
 *备注:默认接收引脚为PC11(USART3-Rx)
 *备注:采用串口DMA双缓冲接收
 *备注:配置定时中断为TIM7 30ms,用来检测遥控器连接情况
 *备注:加入独立看门狗,用来在数据接收错误时复位(只在上电的一刻可能数据错误)
 *备注:独立看门狗时钟为LSI(32kHz),预分频数默认为128,故IWDG时钟250Hz,重装载值为0x0FFF(4095)
 *备注:喂狗时间T_OUT=Reload/(LSI/Prescaler)=4095/(32k/128)=16.38s
 */
void Remote_Init(void)
{
	/*===============配置时钟===============*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);//开启时钟
	
	/*===============配置GPIO===============*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//复用推挽
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//默认上拉
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化USART3-Rx(PC11)
	
	GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_USART3);//开启PC11的USART3复用模式
	
	/*===============配置USART和串口接收DMA===============*/
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate=100000;//配置波特率100k
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//配置无硬件流控制
	USART_InitStructure.USART_Mode=USART_Mode_Rx;//配置为接收模式
	USART_InitStructure.USART_Parity=USART_Parity_Even;//配置为偶校验
	USART_InitStructure.USART_StopBits=USART_StopBits_1;//配置停止位为1
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;//配置字长8bit
	USART_Init(USART3,&USART_InitStructure);//初始化USART3
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_Channel=DMA_Channel_4;//选择DMA通道4
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//普通模式(非自动重装)
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//转运方向为外设到存储器
	DMA_InitStructure.DMA_BufferSize=18;//数据传输量为18字节
	DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;//最高优先级
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(USART3->DR);//外设地址(USART的DR数据接收寄存器)
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//外设突发单次传输
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据长度为1字节(8bits)
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不自增
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)Remote_RxData0;//存储器地址(遥控器DMA数据存储器0)
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//存储器突发单次传输
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//存储器数据长度为1字节(8bits)
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器地址自增
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//不使用FIFO模式
	DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOStatus_1QuarterFull;//设置FIFO阈值为1/4(不使用FIFO模式时,此位无意义)
	DMA_Init(DMA1_Stream1,&DMA_InitStructure);//初始化数据流1
	
	DMA_DoubleBufferModeConfig(DMA1_Stream1,(uint32_t)Remote_RxData1,DMA_Memory_0);//设置双缓冲搬运从遥控器DMA数据存储器0开始
	DMA_DoubleBufferModeCmd(DMA1_Stream1,ENABLE);//使能DMA双缓冲功能
	
	/*===============配置定时器===============*/
	TIM_InternalClockConfig(TIM7);//选择时基单元的时钟(TIM7)
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元（配置参数）
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//配置时钟分频为1分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//配置计数器模式为向上计数
	TIM_TimeBaseInitStructure.TIM_Period=2520-1;//配置自动重装值ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=1000-1;//配置分频值PSC,默认定时30ms
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//配置重复计数单元的置为0
	TIM_TimeBaseInit(TIM7,&TIM_TimeBaseInitStructure);//初始化TIM7
	
	TIM_ClearFlag(TIM7,TIM_FLAG_Update);//清除配置时基单元产生的中断标志位
	
	/*===============配置接收中断和定时器中断===============*/
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//打通USART3到NVIC的串口接收中断通道
	TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);//使能TIM7更新中断
		
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择NVIC分组2(2位抢占优先级,2位响应优先级)
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;//选择USART3中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级为1
	NVIC_Init(&NVIC_InitStructure);//初始化USART3的NVIC
	NVIC_InitStructure.NVIC_IRQChannel=TIM7_IRQn;//选择中断通道为TIM2
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//TIM2的抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//TIM2的响应优先级
	NVIC_Init(&NVIC_InitStructure);//初始化NVIC
	
	/*===============使能===============*/
	DMA_Cmd(DMA1_Stream1,ENABLE);//使能DMA1的数据流1
	USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);//使能串口USART3的DMA搬运
	USART_Cmd(USART3,ENABLE);//启动USART3
	TIM_Cmd(TIM7,ENABLE);//启动定时器
	
	/*===============配置IWDG===============*/
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//
	IWDG_SetPrescaler(IWDG_Prescaler_128);//128分频
	IWDG_SetReload(0x0FFF);//设置重装载值
	IWDG_Enable();
}

/*
 *函数简介:遥控器开启
 *参数说明:无
 *返回类型:无
 *备注:默认开启串口USART3
 */
void Remote_ON(void)
{
	USART_Cmd(USART3,ENABLE);//启动USART3
}

/*
 *函数简介:遥控器关闭
 *参数说明:无
 *返回类型:无
 *备注:默认关闭串口USART3
 */
void Remote_OFF(void)
{
	USART_Cmd(USART3,DISABLE);//失能USART3
	Remote_Status=0;//遥控器连接状态变为未连接
}

/*
 *函数简介:遥控器DMA转运复位
 *参数说明:无
 *返回类型:无
 *备注:无
 */
void Remote_TransferReset(void)
{
	while(DMA_GetFlagStatus(DMA1_Stream1,DMA_FLAG_TCIF1)==RESET);//判断接收完成
	DMA_ClearFlag(DMA1_Stream1,DMA_FLAG_TCIF1);//清除接收完成标志位
	DMA_Cmd(DMA1_Stream1,DISABLE);//失能DMA1的数据流1
	while(DMA_GetCmdStatus(DMA1_Stream1)!=DISABLE);//检测DMA1的数据流1为可配置状态
	DMA_SetCurrDataCounter(DMA1_Stream1,18);//恢复传输计数器的值
	DMA_Cmd(DMA1_Stream1,ENABLE);//使能DMA1的数据流1
}

/*
 *函数简介:遥控器数据处理
 *参数说明:无
 *返回类型:无
 *备注:遥控器接收数据共18Bytes(144bits)
 */
void Remote_DataProcess(void)
{
	uint8_t *Data;//选择存储器
	if(DMA_GetCurrentMemoryTarget(DMA1_Stream1)==0)Data=Remote_RxData1;//若当前转运位于存储器0,则存储器1数据完整,采用存储器1进行数据处理
	else Data=Remote_RxData0;//若当前转运位于存储器1,则存储器0数据完整,采用存储器0进行数据处理
	
	Remote_RxData.Remote_R_RL=(((uint16_t)Data[1]<<8) | Data[0]) & 0x07FF;//B[0:10],11bits
	Remote_RxData.Remote_R_DU=(((uint16_t)Data[2]<<5) | (Data[1]>>3)) & 0x07FF;//B[11:21],11bits
	Remote_RxData.Remote_L_RL=(((uint16_t)Data[4]<<10) | (((uint16_t)Data[3]<<2) | (Data[2]>>6))) & 0x07FF;//B[22:32],11bits
	Remote_RxData.Remote_L_DU=(((uint16_t)Data[5]<<7) | (Data[4]>>1)) & 0x07FF;//B[33:43],11bits
	
	Remote_RxData.Remote_RS=(Data[5]>>4) & 0x03;//B[44:45],2bits
	Remote_RxData.Remote_LS=(Data[5]>>6) & 0x03;//B[46:47],2bits
	
	Remote_RxData.Remote_Mouse_RL=(int16_t)(((uint16_t)Data[7]<<8) | Data[6]);//B[48:63],16bits
	Remote_RxData.Remote_Mouse_DU=(int16_t)(((uint16_t)Data[9]<<8) | Data[8]);//B[64:79],16bits
	Remote_RxData.Remote_Mouse_Wheel=(int16_t)(((uint16_t)Data[11]<<8) | Data[10]);//B[80:95],16bits
	Remote_RxData.Remote_Mouse_KeyL=Data[12];//B[96:103],8bits
	Remote_RxData.Remote_Mouse_KeyR=Data[13];//B[104:111],8bits
	
	Remote_RxData.Remote_Key_W=Data[14] & 0x01;//B[112:112],1bits
	Remote_RxData.Remote_Key_S=(Data[14]>>1) & 0x01;//B[113:113],1bits
	Remote_RxData.Remote_Key_A=(Data[14]>>2) & 0x01;//B[114:114],1bits
	Remote_RxData.Remote_Key_D=(Data[14]>>3) & 0x01;//B[115:115],1bits
	Remote_RxData.Remote_Key_Q=(Data[14]>>4) & 0x01;//B[116:116],1bits
	Remote_RxData.Remote_Key_E=(Data[14]>>5) & 0x01;//B[117:117],1bits
	Remote_RxData.Remote_Key_Shift=(Data[14]>>6) & 0x01;//B[118:118],1bits
	Remote_RxData.Remote_Key_Ctrl=(Data[14]>>7) & 0x01;//B[119:119],1bits
	
	Remote_RxData.Remote_ThumbWheel=(int16_t)((uint16_t)Data[17]<<8) | Data[16];
}

/*
 *函数简介:遥控器接收中断
 *参数说明:无
 *返回类型:无
 *备注:USART的接收中断
 */
void USART3_IRQHandler(void)
{
	TIM_SetCounter(TIM7,0);
	TIM_Cmd(TIM7,DISABLE);//关闭定时器并重置计数值
	if(DMA_GetCurrDataCounter(DMA1_Stream1)==18)//转运一次完成,并交换了存储器
	{
		Remote_TransferReset();//复位DMA1的数据流1
		Remote_DataProcess();//数据处理
		if(Remote_StartFlag==1)//第一次接收数据
		{
			while(Remote_RxData.Remote_R_RL!=1024 || Remote_RxData.Remote_R_DU!=1024 || Remote_RxData.Remote_L_RL!=1024 || Remote_RxData.Remote_L_DU!=1024)//数据错误
				Warming_RemoteDataERROR();//数据错误报错,等待看门狗复位
			Remote_StartFlag=2;
		}
		Remote_Status=1;//遥控器已连接
	}
	TIM_Cmd(TIM7,ENABLE);//开启定时
	
	USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清除接收中断标志位
}
//void USART3_IRQHandler(void)
//{
//	static uint8_t Music_Status=0;
//	if(DMA_GetCurrDataCounter(DMA1_Stream1)==18)//转运一次完成,并交换了存储器
//	{
//		Remote_TransferReset();//复位DMA1的数据流1
//		Remote_DataProcess();//数据处理
//		if(Remote_FirstFlag==1)
//		{
//			Remote_FirstFlag=2;
//			Music_Status=0;
//		}
//		Remote_Status=1;//遥控器已连接
//		
//		if(Remote_LastRxData.Remote_LS==3 && Remote_RxData.Remote_LS==2)
//		{
//			if(Music_Status==0)
//			{
//				Music_Status=1;
//				Music_TIMSingOpen();
//			}
//			else
//			{
//				Music_Status=0;
//				Music_TIMSingClose();
//			}
//		}

//	}
//	
//	USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清除接收中断标志位
//}

/*
 *函数简介:TIM2定时器更新中断函数
 *参数说明:无
 *返回类型:无
 *备注:无
 */
void TIM7_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM7,TIM_IT_Update)==SET)//检测TIM2更新
	{
		TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除标志位
		Warming_RemoteNoCheck();
		Remote_Status=0;
		Remote_StartFlag=1;
	}
}

